#include "test_bit_win_xml.h"

#include "bitwin/model_templates.h"

#include <memory>


using namespace BitWin;


typedef std::auto_ptr<QAbstractTableModel> PModel;


void TestBitWinXml::testMakeModelHeaders_data()
{
    QTest::addColumn<QDomElement>("xml_data");
    QTest::addColumn<QStringList>("row_headers");
    QTest::addColumn<QStringList>("column_headers");
    
    QTest::newRow("empty DOM element")
        << QDomElement()
        << QStringList() << QStringList()
    ;
    QTest::newRow("Element with no rows")
        << createDoc(
            "<no_rows>"
                "<columns>"
                    "<bin title='Column #1' bits ='3:2'/>"
                    "<bin title='Column No. 2' bits ='1:0'/>"
                "</columns>"
            "</no_rows>"
        )
        << QStringList()
        << (QStringList() << "Column #1" << "Column No. 2")
    ;
    QTest::newRow("Element with no columns")
        << createDoc(
            "<no_columns>"
                "<rows>"
                    "<word title='Row-1'/>"
                    "<word title='Row2'/>"
                "</rows>"
            "</no_columns>"
        )
        << (QStringList() << "Row-1" << "Row2")
        << QStringList()
    ;
    QTest::newRow("valid DOM element")
        << createDoc(
            "<valid>"
                "<rows>"
                    "<word title='Row #1'>"
                        "<field title='Row No. 2' bits='15:9'/>"
                        "<field title='Row-3' bits='8:0'/>"
                    "</word>"
                "</rows>"
                "<columns>"
                    "<bin title='Column-1' bits='15:11'/>"
                    "<bin title='Column 2' bits='10:9'/>"
                    "<bin title='Col. No. 3' bits='8:6'/>"
                    "<bin title='Column #4' bits='5:0'/>"
                    "<hex title='Hex column #1'/>"
                    "<dec title='Dec column-1'/>"
                    "<hex title='Hex column.2'/>"
                    "<dec title='Dec column No.2'/>"
                "</columns>"
            "</valid>"
        )
        << (
                QStringList()
                    << "Row #1" << "Row No. 2" << "Row-3"
            )
        << (
                QStringList()
                    << "Column-1" << "Column 2"
                    << "Col. No. 3" << "Column #4"
                    << "Hex column #1"
                    << "Dec column-1"
                    << "Hex column.2"
                    << "Dec column No.2"
            )
    ;
}

void TestBitWinXml::testMakeModelHeaders()
{
    #define COMPARE_HEADERS(expected, model, orientation, role) \
    for (int i = 0; i < expected.size(); ++i) \
        QCOMPARE( \
            model->headerData(i, orientation, role).value<QString>(), \
            expected.value(i) \
        );
    
    QFETCH(QDomElement, xml_data);
    QAbstractTableModel* model = FromXml::makeModel(xml_data);
    QVERIFY(model);
    PModel model_holder(model);
    
    QFETCH(QStringList, row_headers);
    QCOMPARE(model->rowCount(), row_headers.size());
    COMPARE_HEADERS(row_headers, model, Qt::Vertical, Qt::DisplayRole);
    
    QFETCH(QStringList, column_headers);
    QCOMPARE(model->columnCount(), column_headers.size());
    COMPARE_HEADERS(column_headers, model, Qt::Horizontal, Qt::DisplayRole);
    
    #undef COMPARE_HEADERS
}

void TestBitWinXml::testMakeModelData_data()
{
    QTest::addColumn<QStringList>("indata");
    QTest::addColumn<role_t>("role");
    QTest::addColumn<int>("row");
    QTest::addColumn<int>("column");
    QTest::addColumn<QString>("outdata_expected");
    
    QTest::newRow("word 0, column 0")
        << (QStringList() << "abcde")
        << BITWISE_DATA_ROLE
        << 0 << 0 << QString("e")
    ;
    QTest::newRow("word 0, column 1")
        << (QStringList() << "abcde")
        << BITWISE_DATA_ROLE
        << 0 << 1 << QString("bcd")
    ;
    QTest::newRow("word 0, column 2")
        << (QStringList() << "abcde")
        << BITWISE_DATA_ROLE
        << 0 << 2 << QString("a")
    ;
    
    QTest::newRow("word 0, field 0, column 0")
        << (QStringList() << "abcde")
        << BITWISE_DATA_ROLE
        << 1 << 0 << QString("e")
    ;
    QTest::newRow("word 0, field 0, column 1")
        << (QStringList() << "abcde")
        << BITWISE_DATA_ROLE
        << 1 << 1 << QString("  d")
    ;
    QTest::newRow("word 0, field 0, column 2")
        << (QStringList() << "abcde")
        << BITWISE_DATA_ROLE
        << 1 << 2 << QString(" ")
    ;
    QTest::newRow("word 0, field 1, column 0")
        << (QStringList() << "abcde")
        << BITWISE_DATA_ROLE
        << 2 << 0 << QString(" ")
    ;
    QTest::newRow("word 0, field 1, column 1")
        << (QStringList() << "abcde")
        << BITWISE_DATA_ROLE
        << 2 << 1 << QString("bc ")
    ;
    QTest::newRow("word 0, field 1, column 2")
        << (QStringList() << "abcde")
        << BITWISE_DATA_ROLE
        << 2 << 2 << QString("a")
    ;
    
    QTest::newRow("word 1, column 1, no data available")
        << (QStringList() << "abcde")
        << BITWISE_DATA_ROLE
        << 3 << 1 << QString("   ")
    ;
    QTest::newRow("word 1, column 0")
        << (QStringList() << "abcde" << "fghjk")
        << BITWISE_DATA_ROLE
        << 3 << 0 << QString("k")
    ;
    QTest::newRow("word 1, column 1")
        << (QStringList() << "abcde" << "fghjk")
        << BITWISE_DATA_ROLE
        << 3 << 1 << QString("ghj")
    ;
    QTest::newRow("word 1, column 2")
        << (QStringList() << "abcde" << "fghjk")
        << BITWISE_DATA_ROLE
        << 3 << 2 << QString("f")
    ;
    QTest::newRow("word 1, field 0, column 0")
        << (QStringList() << "abcde" << "fghjk")
        << BITWISE_DATA_ROLE
        << 4 << 0 << QString("k")
    ;
    QTest::newRow("word 1, field 0, column 1")
        << (QStringList() << "abcde" << "fghjk")
        << BITWISE_DATA_ROLE
        << 4 << 1 << QString("ghj")
    ;
    QTest::newRow("word 1, field 0, column 2")
        << (QStringList() << "abcde" << "fghjk")
        << BITWISE_DATA_ROLE
        << 4 << 2 << QString(" ")
    ;
    QTest::newRow("word 1, field 1, column 0")
        << (QStringList() << "abcde" << "fghjk")
        << BITWISE_DATA_ROLE
        << 5 << 0 << QString(" ")
    ;
    QTest::newRow("word 1, field 1, column 1")
        << (QStringList() << "abcde" << "fghjk")
        << BITWISE_DATA_ROLE
        << 5 << 1 << QString("   ")
    ;
    QTest::newRow("word 1, field 1, column 2")
        << (QStringList() << "abcde" << "fghjk")
        << BITWISE_DATA_ROLE
        << 5 << 2 << QString("f")
    ;
    
    QTest::newRow("word 0, hex column")
        << (QStringList() << "abcde" << "fghjk")
        << role_t(Qt::DisplayRole)
        << 0 << 3 << QString("HEX(abcde)")
    ;
    QTest::newRow("word 1, dec column")
        << (QStringList() << "abcde" << "fghjk")
        << role_t(Qt::DisplayRole)
        << 3 << 4 << QString("DEC(fghjk)")
    ;
}

void TestBitWinXml::testMakeModelData()
{
/*
    Table should look like this:

           |         | C#3 |    Column #2    | C#1 | C#4 | C#5 
    -------+---------+-----+-----------------+-----+-----+-----
       0   |word   #1|  a  |  b     c     d  |  e  | HEX | DEC 
    -------+---------+-----+-----------------+-----+-----+-----
       1   |field 1-1|     |              d  |  e  |     |     
    -------+---------+-----+-----------------+-----+-----+-----
       2   |field 1-2|  a  |  b     c        |     |     |     
    -------+---------+-----+-----------------+-----+-----+-----
       3   |word   #2|  f  |  g     h     j  |  k  | HEX | DEC 
    -------+---------+-----+-----------------+-----+-----+-----
       4   |field 2-1|     |  g     h     j  |  k  |     |     
    -------+---------+-----+-----------------+-----+-----+-----
       5   |field 2-2|  f  |                 |     |     |     
    -------+---------+-----+-----------------+-----+-----+-----
*/
    
    QDomElement xml_data(createDoc(
        "<?xml version='1.0' encoding='UTF-8'?>"
        "<model>"
            "<rows>"
                "<word title='word #1'>"
                    "<field title='field 1-1' bits='4:3'/>"
                    "<field title='field 1-2' bits='2:0'/>"
                "</word>"
                "<word title='word #2'>"
                    "<field title='field 2-1' bits='4:1'/>"
                    "<field title='field 2-2' bits='0'/>"
                "</word>"
            "</rows>"
            "<columns>"
                "<bin title='column 1' bits='4'/>"
                "<bin title='column 2' bits='3:1'/>"
                "<bin title='column 3' bits='0'/>"
                "<hex title='column 4'/>"
                "<dec title='column 5'/>"
            "</columns>"
        "</model>"
    ));
    
    QVERIFY(!xml_data.isNull());
    Model* model = FromXml::makeModel(xml_data);
    QVERIFY(model);
    
    PModel model_holder(model);
    
    QCOMPARE(model->rowCount(), 6);
    QCOMPARE(model->columnCount(), 5);
    
    QFETCH(QStringList, indata);
    model->commitData<GenericBitwise::FromSequence>(
        indata.begin(), indata.end()
    );
    
    QFETCH(role_t, role);
    QFETCH(int, row);
    QFETCH(int, column);
    QModelIndex index(model->index(row, column));
    QVERIFY(index.isValid());
    
    QVariant data(model->data(index, role));
    QVERIFY(data.isValid());
    QVERIFY(data.canConvert<QString>());
    
    QFETCH(QString, outdata_expected);
    QCOMPARE(data.value<QString>(), outdata_expected);
}
